终章 --- Response Send And Terminate
简介
终于。。。终章了。。。
上一章,完成响应头的设置后,最后一行的 return $this
,就会把响应抛回入口文件,当然中间经过 EncryptCookies
这类中间件,会对响应进行再次处理。
让我们回到当年开始的地方,因为我们的初心在那里。。
public/index.php
// 省略上面一些不相关的代码...
/*
* handle 函数,你就是一个神仙,运行你,跑这么深的地方,到现在才回来。。。
* 行了,不吐槽了,$response 就是 `Symfony\Component\HttpFoundation\Response` 的实例化对象
*/
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
// 将响应头和响应体返回给浏览器
$response->send();
// 调用所有在用中间件的终止函数,调用容器的终值函数,做 Laravel 最后的收尾工作。
$kernel->terminate($request, $response);
我们来看一下 Response 的 send 函数
Symfony\Component\HttpFoundation\Response
public function send()
{
// 调用 PHP 的 header 函数,将响应头数据全部返回给浏览器
$this->sendHeaders();
// 调用 PHP 的 echo 语句,将响应体数据加入到 PHP 的输出控制缓存中
$this->sendContent();
// 将 PHP 输出控制缓存中的数据返回给浏览器
if (\function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
} elseif (!\in_array(\PHP_SAPI, array('cli', 'phpdbg'), true)) {
static::closeOutputBuffers(0, true);
}
return $this;
}
sendHeaders 函数
Symfony\Component\HttpFoundation\Response
public function sendHeaders()
{
// headers_sent(),当 PHP 已发送响应头数据,返回 true,否则返回 false
if (headers_sent()) {
return $this;
}
// 从 Response 对象中获取响应头数据,使用 header 函数向浏览器输出 响应头
foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
foreach ($values as $value) {
header($name.': '.$value, false, $this->statusCode);
}
}
// 将 Cookies 返回给浏览器
foreach ($this->headers->getCookies() as $cookie) {
header('Set-Cookie: '.$cookie->getName().strstr($cookie, '='), false, $this->statusCode);
}
// 将类似 HTTP/1.0 200 success 这样的响应码信息,返回给浏览器
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);
return $this;
}
sendContent 函数
Symfony\Component\HttpFoundation\Response
public function sendContent()
{
// 不要误解,这里仅仅只是将 响应体 输出到 PHP 的控制输出缓存中,还没向浏览器发送数据。
echo $this->content;
return $this;
}
关于 PHP 的输出缓存控制
为什么要用缓存控制?
header
函数官方有一句话: 请注意 header() 必须在任何实际输出之前调用,不管是普通的 HTML 标签,还是文件或 PHP 输出的空行,空格。官方文档地址
这就造成一个问题,如果我们在 Laravel 控制器中 echo 一段内容,而框架假设没有使用 PHP 的输出控制,那么就会造成 响应头 无法发送到浏览器中。
关于输出控制怎么用
官方范例很好体现了输出缓存控制的使用 --> 传送门
终止函数 Terminate
所谓终止,其实是 Laravel 运行生命周期结束前的最后处理。处理什么呢?
一是 所有中间件 结尾处理,当然中间件必须有 terminate 方法才行。
例如:
StartSession
这个中间件。public function terminate($request, $response)
{
if ($this->sessionHandled && $this->sessionConfigured() && ! $this->usingCookieSessions()) {
// 调用 Session 的 save 方法,向 Laravel 的 storage 中写 session 会话数据
$this->manager->driver()->save();
}
}save 方法
public function save()
{
$this->ageFlashData();
// 序列化当前会话,并保存到 Laravel storage 中。。
$this->handler->write($this->getId(), $this->prepareForStorage(
serialize($this->attributes)
));
$this->started = false;
}容器终止
public function terminate()
{
// 将终止属性数组中的所有终止闭包函数执行掉。。
foreach ($this->terminatingCallbacks as $terminating) {
$this->call($terminating);
}
}/**
* 当前方法,就是容器终止属性数组添加终止闭包函数的地方,这里请根据我们项目需要进行调用
*/
public function terminating(Closure $callback)
{
$this->terminatingCallbacks[] = $callback;
return $this;
}
- 最后说一下